package prolog.fluents

import java.util.{ArrayList,Iterator};
//import java.util.;
import java.util.NoSuchElementException;
import prolog.io.IO;
import prolog.terms.Term;



/**
This class implementes generic multiple tuples by key
operations for use by the PrologBlackBoard class implementing
Linda operations on Prolog terms. It uses the Queue class for
keeping elements of type Term sharing the same key.

@see PrologBlackBoard
@see Queue
@see Term
*/
class BlackBoard1 extends prolog.fluents.HashDict1{
 
  def BlackBoard1(){
    //super();
  }
    
  // synchronized
  private final pick(k:String):Term = {
    if(k==null) {
      Iterator e=this.keySet().iterator();
      if(!e.hasNext())
        return null;
      k=(String)e.next();
      // IO.trace("$$Got key:"+k+this);
    }
    Queue Q=(Queue)get(k);
    if(Q==null)
      return null;
    Term T=(Term)Q.deq();
    if(Q.isEmpty()) {
      remove(k);
      // IO.trace("$$Removed key:"+k+this);
    }
     T;
  }
  
  private final addBack(k:String,V:ArrayList):Unit = {
    for(Iterator e=V.iterator();e.hasNext();) {
      // cannot be here if k==null
      add(k,(Term)e.next());
    }
  }

  // synchronized
  protected final take(k:String,pattern:Term):Term = {
    ArrayList V=new ArrayList();
    Term t;
    while(true) {
      t=pick(k);
      if(null==t)
        break;
      // IO.trace("$$After pick: t="+t+this);
      if(t.matches(pattern))
        break;
      else
        V.add(t);
    }
    addBack(k,V);
    t;
  }
  
  // synchronized
  protected final add(k:String,Value:Term):Unit = {
    Queue Q=(Queue)get(k);
    if(Q==null) {
      Q=new Queue();
      put(k,Q);
    }
    if(!Q.enq(value))
      IO.errmes("Queue full, key:"+k);
    // IO.trace("$$Added key/val:"+k+"/"+value+"=>"+this);
  }
    // synchronized
  def toEnumerationFor(k:String):Iterator = {
    Queue Q=(Queue)get(k);
    ArrayList V=(Q==null)?new ArrayList():Q.toVector();
    V.iterator();
  }
    // synchronized
  def toEnumeration():Iterator = {
     new BBoardEnumerator(this.keySet().iterator());
  }
  }

class BBoardEnumerator with Iterator {
  BBoardEnumerator(EH:Iterator){
    EQ=null;
    this.EH=EH; // elements();
  }
  private var EQ:Iterator;
  private var EH:Iterator;
  
  // synchronized
  def hasNext():boolean = {
    if((EQ==null||!EQ.hasNext())&&EH.hasNext()) {
      EQ=((Queue)EH.next()).toEnumeration();
    }
    (EQ!=null&&EQ.hasNext());
  }
  
  // synchronized
  def next():Object = {
    if(hasNext())
      return EQ.next();
    throw new NoSuchElementException("BBoardEnumerator");
  }
  
    def remove():Unit = {}
}